| ||| | |||||| | ||| |||| on Tue, 2 Mar 2004 20:07:55 +0100 (CET) |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
| [nettime-lat] no-content.net vintage collection ||| GameOfLife.java |
\|/
|
|
¯¯¯¯°¬| @ | - - -> [ ----øøøø---- ] <- - - - - - o
| http://no-content.net/vintage/collection |
0 0 0 0 <0> 0
<|> \|/ \|\ /|\ | <|>
/ \ / \ / \ / \ / \ / \
o - - - - - - - - - - - - - - - - - - - - - - - o
no-content.net/vintage/collection
presents:
pack# 0000 0001 // GameOfLife.java
......
\|/ ¯`·.¸¸.·´¯`·.¸¸.·´¯¯`·¸
|
|
__+__netart.org.uy__________
----- Original Message -----
/**
* Game of Life v1.4
* Copyright 1996-2001 Edwin Martin <edwin-at-bitstorm.nl>
* version 1.0 online since July 3 1996
* Changes:
* 1.1: Double buffering to screen; faster paint
* 1.2: Arrowkeys changed; better use of `synchronized'
* 1.3: Choose speed from drop down menu and draw with mouse
* 1.4: Use Java 1.1 events, remove 13 deprecated methods, some refactoring.
2003-11-08
* @author Edwin Martin
*
*/
package org.bitstorm.gameoflife;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.*;
/**
*
* The Game Of Life Applet.
* @author Edwin Martin
*/
public class GameOfLife extends Applet implements Runnable {
protected GameOfLifeCanvas gameOfLifeCanvas;
protected GameOfLifeGrid gameOfLifeGrid;
protected int cellSize;
protected int cellCols;
protected int cellRows;
protected int genTime;
protected GameOfLifeControls controls;
private static Thread gameThread = null;
private final String VIRGIN = "First draw a shape or select a shape
from\nthe pull-down menu.";
/**
* Initialize UI.
* @see java.applet.Applet#init()
*/
public void init() {
getParams();
// set background colour
setBackground(new Color(0x999999));
// create gameOfLifeGrid
gameOfLifeGrid = new GameOfLifeGrid(cellCols, cellRows);
// create GameOfLifeCanvas
gameOfLifeCanvas = new GameOfLifeCanvas(gameOfLifeGrid, cellSize);
// create GameOfLifeControls
controls = new GameOfLifeControls( this );
// put it all together
setLayout(new BorderLayout());
add(BorderLayout.SOUTH, controls);
add(BorderLayout.NORTH, gameOfLifeCanvas);
setVisible(true);
validate();
}
protected void getParams() {
// get applet parameters: cellSize, cellCols, cellRows, genTime
cellSize = getParamInteger( "cellsize", 11 );
cellCols = getParamInteger( "cellcols", 50 );
cellRows = getParamInteger( "cellrows", 30 );
genTime = getParamInteger( "gentime", 500 );
}
/**
* Read applet parameter (int) or, when unavailable, get default value.
* @param name name of parameter
* @param defaultParam default when parameter is unavailable
* @return value of parameter
*/
protected int getParamInteger( String name, int defaultParam ) {
String param;
int paramInt;
param = getParameter( name );
if ( param == null )
paramInt = defaultParam;
else
paramInt = Integer.valueOf(param).intValue();
return paramInt;
}
/**
* Starts creating new generations.
* No start() to prevent starting immediately.
*/
public synchronized void start2() {
if ( gameOfLifeGrid.isEmpty() ) {
alert( VIRGIN );
} else {
controls.start();
if (gameThread == null) {
gameThread = new Thread(this);
gameThread.start();
}
}
}
/**
* @see java.applet.Applet#stop()
*/
public void stop() {
controls.stop();
gameThread = null;
}
/**
* @see java.lang.Runnable#run()
*/
public synchronized void run() {
while (gameThread != null) {
nextGeneration();
try {
Thread.sleep(genTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* Is the applet running?
* @return true: applet is running
*/
public boolean isRunning() {
return gameThread != null;
}
/**
* Go to the next generation.
*/
public void nextGeneration() {
if ( gameOfLifeGrid.isEmpty() ) {
alert( VIRGIN );
} else {
gameOfLifeGrid.next();
gameOfLifeCanvas.repaint();
showGenerations();
}
}
/**
* Set the new shape
* @param shapeName name of shape
*/
public void setShape( String shapeName ) {
try {
gameOfLifeGrid.setShape( shapeName );
reset();
} catch (ShapeException e) {
alert( e.getMessage() );
}
}
/**
* Resets applet (after loading new shape)
*/
public void reset() {
stop(); // might otherwise confuse user
gameOfLifeCanvas.repaint();
showGenerations();
showStatus( "" );
}
/**
* @see java.applet.Applet#getAppletInfo()
*/
public String getAppletInfo() {
return "Game Of Life v. 1.4\nCopyright 1996-2003 Edwin Martin";
}
/**
* Show number of generations.
*/
private void showGenerations() {
controls.setGeneration( gameOfLifeGrid.getGenerations() );
}
/**
* Set speed of new generations.
* @param fps generations per second
*/
public void setSpeed( int fps ) {
genTime = fps;
}
/**
* Shows an alert
* @param s text to show
*/
public void alert( String s ) {
showStatus( s );
}
}
/**
* Controls of the Game of Life (Shape and speed selector, next and
start/stop-button).
* @author Edwin Martin
*
*/
class GameOfLifeControls extends Panel {
private Label genLabel;
private final String genLabelText = "Generations: ";
private final String slow = "Slow";
private final String fast = "Fast";
private final String hyper = "Hyper";
private final String nextLabelText = "Next";
private final String startLabelText = "Start";
private final String stopLabelText = "Stop";
private Button startstopButton;
private Button nextButton;
private GameOfLife gameOfLife;
/**
* Contructor
* @param gof parent Game Of Life object
*/
public GameOfLifeControls( GameOfLife gameOfLife ) {
this.gameOfLife = gameOfLife;
// pulldown menu with shapes
Choice shapesChoice = new Choice();
// Put names of shapes in menu
Enumeration shapes = GameOfLifeGrid.getShapes();
while (shapes.hasMoreElements()) {
shapesChoice.addItem((String) shapes.nextElement());
}
// when shape is selected
shapesChoice.addItemListener(
new ItemListener() {
public void itemStateChanged(ItemEvent e) {
String shapeName = (String) e.getItem();
getGameOfLife().setShape( shapeName );
}
}
);
// pulldown menu with speeds
Choice speedChoice = new Choice();
// add speeds
speedChoice.addItem(slow);
speedChoice.addItem(fast);
speedChoice.addItem(hyper);
// when item is selected
speedChoice.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
String arg = (String) e.getItem();
if (slow.equals(arg)) // slow
getGameOfLife().setSpeed(1000);
else if (fast.equals(arg)) // fast
getGameOfLife().setSpeed(100);
else if (hyper.equals(arg)) // hyperspeed
getGameOfLife().setSpeed(10);
}
});
// number of generations
genLabel = new Label(genLabelText+"0 ");
// start and stop buttom
startstopButton = new Button(startLabelText);
// when start/stop button is clicked
startstopButton.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
startStopButtonClicked();
}
}
);
// next generation button
nextButton = new Button(nextLabelText);
// when next button is clicked
nextButton.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
getGameOfLife().nextGeneration();
}
}
);
// create panel with controls
this.add(shapesChoice);
this.add(nextButton);
this.add(startstopButton);
this.add(speedChoice);
this.add(genLabel);
this.validate();
}
/**
* Set the number of generations in the control bar.
* @param generations number of generations
*/
public void setGeneration( int generations ) {
genLabel.setText(genLabelText + generations);
}
/**
* Change the label of the start/stop-button to "Stop".
*/
public void start() {
startstopButton.setLabel(stopLabelText);
}
/**
* Change the label of the start/stop-button to "Start".
*/
public void stop() {
startstopButton.setLabel(startLabelText);
}
/**
* Called when the start/stop-button is clicked.
*/
public void startStopButtonClicked() {
if ( gameOfLife.isRunning() ) {
gameOfLife.stop();
} else {
gameOfLife.start2();
}
}
/**
* Return GameOfLife applet object.
* @return GameOfLife applet object
*/
public GameOfLife getGameOfLife() {
return gameOfLife;
}
}
/**
*
* Subclass of Canvas which deals with the GameOfLife.
* @author Edwin Martin
*/
class GameOfLifeCanvas extends Canvas {
private boolean cellUnderMouse;
private Image offScreenImage = null;
private Graphics offScreenGraphics;
private int cellSize;
private GameOfLifeGrid gameOfLifeGrid;
/**
* Constructor.
* @param gameOfLifeGrid
* @param cellSize size of cell in pixels
*/
public GameOfLifeCanvas(GameOfLifeGrid gameOfLifeGrid, int cellSize) {
this.gameOfLifeGrid = gameOfLifeGrid;
this.cellSize = cellSize;
gameOfLifeGrid.clear();
addMouseListener(
new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
draw(e.getX(), e.getY());
}
public void mousePressed(MouseEvent e) {
saveCellUnderMouse(e.getX(), e.getY());
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
draw(e.getX(), e.getY());
}
});
}
/**
* Remember state of cell for drawing.
*
* @param x x-coordinate
* @param y y-coordinate
*/
public void saveCellUnderMouse(int x, int y) {
try {
cellUnderMouse = gameOfLifeGrid.getCell(x / cellSize, y / cellSize);
} catch (java.lang.ArrayIndexOutOfBoundsException e) {
// ignore
}
}
/**
* Draw in this cell.
*
* @param x x-coordinate
* @param y y-coordinate
*/
public void draw(int x, int y) {
try {
gameOfLifeGrid.setCell(x / cellSize, y / cellSize, !cellUnderMouse );
repaint();
gameOfLifeGrid.notEmpty();
} catch (java.lang.ArrayIndexOutOfBoundsException e) {
// ignore
}
}
/**
* Use double buffering.
* @see java.awt.Component#update(java.awt.Graphics)
*/
public void update(Graphics theG) {
Dimension d = getSize();
if ((offScreenImage == null)) {
offScreenImage = createImage(d.width, d.height);
offScreenGraphics = offScreenImage.getGraphics();
}
paint(offScreenGraphics);
theG.drawImage(offScreenImage, 0, 0, null);
}
/**
* Draw this generation.
* @see java.awt.Component#paint(java.awt.Graphics)
*/
public void paint(Graphics g) {
// draw background (MSIE doesn't do that)
Dimension dim = gameOfLifeGrid.getDimension();
g.setColor(Color.gray);
g.fillRect(0, 0, cellSize * dim.width - 1, cellSize * dim.height - 1);
// draw grid
g.setColor(getBackground());
for (int x = 1; x < dim.width; x++) {
g.drawLine(x * cellSize - 1, 0, x * cellSize - 1, cellSize * dim.height -
1);
}
for (int y = 1; y < dim.height; y++) {
g.drawLine( 0, y * cellSize - 1, cellSize * dim.width - 1, y * cellSize -
1);
}
// draw populated cells
g.setColor(Color.yellow);
for (int y = 0; y < dim.height; y++) {
for (int x = 0; x < dim.width; x++) {
if (gameOfLifeGrid.getCell(x, y)) {
g.fillRect(x * cellSize, y * cellSize, cellSize - 1, cellSize - 1);
}
}
}
}
/**
* This is the preferred size.
* @see java.awt.Component#getPreferredSize()
*/
public Dimension getPreferredSize() {
Dimension dim = gameOfLifeGrid.getDimension();
return new Dimension( cellSize * dim.width, cellSize * dim.height );
}
}
/**
* Contains all the Game Of Life algorithms and shapes.
*
* @author Edwin Martin
*/
class GameOfLifeGrid {
protected boolean cells[][];
protected int cellRows;
protected int cellCols;
protected int cellsBuffer[][];
private int generations;
private static Shape[] shapes;
private boolean empty;
static {
// define all available shapes
shapes = new Shape[8];
shapes[0] = new Shape("Clear", new int[][] {} );
shapes[1] = new Shape("Glider", new int[][] {{0,1}, {1,2}, {2,2}, {2,1},
{2,0}});
shapes[2] = new Shape("Small Exploder", new int[][] {{0,1}, {0,2}, {1,0},
{1,1}, {1,3}, {2,1}, {2,2}});
shapes[3] = new Shape("Exploder", new int[][] {{0,0}, {0,1}, {0,2}, {0,3},
{0,4}, {2,0}, {2,4}, {4,0}, {4,1}, {4,2}, {4,3}, {4,4}});
shapes[4] = new Shape("10 Cell Row", new int[][] {{0,0}, {1,0}, {2,0},
{3,0}, {4,0}, {5,0}, {6,0}, {7,0}, {8,0}, {9,0}});
shapes[5] = new Shape("Fish", new int[][] {{0,1}, {0,3}, {1,0}, {2,0},
{3,0}, {3,3}, {4,0}, {4,1}, {4,2}});
shapes[6] = new Shape("Pump", new int[][] {{0,3}, {0,4}, {0,5}, {1,0},
{1,1}, {1,5}, {2,0}, {2,1}, {2,2}, {2,3}, {2,4}, {4,0}, {4,1}, {4,2}, {4,3},
{4,4}, {5,0}, {5,1}, {5,5}, {6,3}, {6,4}, {6,5}});
shapes[7] = new Shape("Shooter", new int[][] {{0,2}, {0,3}, {1,2}, {1,3},
{8,3}, {8,4}, {9,2}, {9,4}, {10,2}, {10,3}, {16,4}, {16,5}, {16,6}, {17,4},
{18,5}, {22,1}, {22,2}, {23,0}, {23,2}, {24,0}, {24,1}, {24,12}, {24,13},
{25,12}, {25,14}, {26,12}, {34,0}, {34,1}, {35,0}, {35,1}, {35,7}, {35,8},
{35,9}, {36,7}, {37,8}});
}
/**
* Contructor.
*
* @param cellCols number of columns
* @param cellRows number of rows
*/
public GameOfLifeGrid(int cellCols, int cellRows) {
this.cellCols = cellCols;
this.cellRows = cellRows;
cellsBuffer = new int[cellCols][cellRows];
cells = new boolean[cellCols][cellRows];
empty = true;
}
/**
* @return enumeration of shapes
*/
public static Enumeration getShapes() {
return new ShapeEnumeration( shapes );
}
/**
* Clears grid.
*/
public void clear() {
generations = 0;
//virgin = true;
for (int x = 0; x < cellCols; x++) {
for (int y = 0; y < cellRows; y++) {
cells[x][y] = false;
}
}
}
/**
* Create next generation of shape.
*/
public synchronized void next() {
int x;
int y;
generations++;
// clear the buffer
for (x = 0; x < cellCols; x++) {
for (y = 0; y < cellRows; y++) {
cellsBuffer[x][y] = 0;
}
}
// count neighbors of off-edge cells
for (x = 1; x < cellCols - 1; x++) {
for (y = 1; y < cellRows - 1; y++) {
if (cells[x][y]) {
cellsBuffer[x - 1][y - 1]++;
cellsBuffer[x][y - 1]++;
cellsBuffer[x + 1][y - 1]++;
cellsBuffer[x - 1][y]++;
cellsBuffer[x + 1][y]++;
cellsBuffer[x - 1][y + 1]++;
cellsBuffer[x][y + 1]++;
cellsBuffer[x + 1][y + 1]++;
}
}
}
// count neighbors of edge cells
x = 1; // start at (1,0)
y = 0;
int dx = 1;
int dy = 0;
while (true) {
if (cells[x][y]) {
if (x > 0) {
if (y > 0)
cellsBuffer[x - 1][y - 1]++;
if (y < cellRows - 1)
cellsBuffer[x - 1][y + 1]++;
cellsBuffer[x - 1][y]++;
}
if (x < cellCols - 1) {
if (y < cellRows - 1)
cellsBuffer[x + 1][y + 1]++;
if (y > 0)
cellsBuffer[x + 1][y - 1]++;
cellsBuffer[x + 1][y]++;
}
if (y > 0)
cellsBuffer[x][y - 1]++;
if (y < cellRows - 1)
cellsBuffer[x][y + 1]++;
}
// turn clockwise at collision with edge
if (x == cellCols - 1 ) {
if (y == 0) {
dx = 0;
dy = 1;
} else if ( y == cellRows - 1) {
dx = -1;
dy = 0;
}
} else if (x == 0) {
if ( y == cellRows - 1) {
dx = 0;
dy = -1;
} else if ( y == 0) {
// all edge cells done
break;
}
}
x += dx;
y += dy;
}
// here is the life algorithm
// simple, isn't it?
for (x = 0; x < cellCols; x++) {
for (y = 0; y < cellRows; y++) {
switch (cellsBuffer[x][y]) {
case 2 :
// no change
break;
case 3 :
cells[x][y] = true;
break;
default :
cells[x][y] = false;
break;
}
}
}
}
/**
* Draws shape in grid.
*
* @param shapeName name of shape
* @return true when shape fits, false otherwise
*/
public synchronized void setShape(String shapeName) throws ShapeException {
int xOffset;
int yOffset;
int[][] shape = null;
Dimension dim = null;
int i;
notEmpty();
for ( i = 0; i < shapes.length; i++ ) {
if ( shapes[i].getName().equals( shapeName ) )
break;
}
// not found
if ( i == shapes.length )
throw new ShapeException( "Unknown shape" ); // shape doesn't fit on
canvas
// get shape properties
shape = shapes[i].getShape();
dim = shapes[i].getDimension();
if (dim.width > cellCols || dim.height > cellRows)
throw new ShapeException( "Shape doesn't fit on canvas" ); // shape
doesn't fit on canvas
// center the shape
xOffset = (cellCols - dim.width) / 2;
yOffset = (cellRows - dim.height) / 2;
clear();
// draw shape
for ( i = 0; i < shape.length; i++ )
cells[xOffset + shape[i][0]][yOffset + shape[i][1]] = true;
}
/**
* Get value of cell.
* @param x x-coordinate of cell
* @param y y-coordinate of cell
* @return value of cell
*/
public boolean getCell( int x, int y ) {
try {
return cells[x][y];
} catch (ArrayIndexOutOfBoundsException e) {
return false;
}
}
/**
* Set value of cell.
* @param x x-coordinate of cell
* @param y y-coordinate of cell
* @param c value of cell
*/
public void setCell( int x, int y, boolean c ) {
try {
cells[x][y] = c;
} catch (ArrayIndexOutOfBoundsException e) {
// ignore
}
}
/**
* @return number of generations
*/
public int getGenerations() {
return generations;
}
/**
* @return dimension of grid
*/
public Dimension getDimension() {
return new Dimension( cellCols, cellRows );
}
/**
* Grid is not empty anymore
*/
public void notEmpty() {
empty = false;
}
/**
* Is grid empty?
* @return true if empty, false otherwise
*/
public boolean isEmpty() {
return empty;
}
}
/**
* Shape contains data of one shape.
*
* @author Edwin Martin
*/
class Shape {
private String name;
private int[][] shape;
/**
* Constructor.
* @param name name of shape
* @param shape shape data
*/
public Shape( String name, int[][] shape ) {
this.name = name;
this.shape = shape;
}
/**
* @return dimension of the shape in cells
*/
public Dimension getDimension() {
int shapeWidth = 0;
int shapeHeight = 0;
for (int cell = 0; cell < shape.length; cell++) {
if (shape[cell][0] > shapeWidth)
shapeWidth = shape[cell][0];
if (shape[cell][1] > shapeHeight)
shapeHeight = shape[cell][1];
}
shapeWidth++;
shapeHeight++;
return new Dimension( shapeWidth, shapeHeight );
}
/**
* @return name of shape
*/
public String getName() {
return name;
}
/**
* @return shape data
*/
public int[][] getShape() {
return shape;
}
}
/**
*
* Enumerate through array of shapes.
*
* @author Edwin Martin
*/
class ShapeEnumeration implements Enumeration {
private int index;
private Shape[] shapes;
/**
* Contructor.
* @param shapes
*/
public ShapeEnumeration( Shape[] shapes ) {
index = 0;
this.shapes = shapes;
}
/**
* @see java.util.Enumeration#hasMoreElements()
*/
public boolean hasMoreElements() {
return index < shapes.length;
}
/**
* @see java.util.Enumeration#nextElement()
*/
public Object nextElement() {
index++;
return shapes[index-1].getName();
}
}
/**
* Exception for shapes (too big, not found...).
*
* @author Edwin Martin
*/
class ShapeException extends Exception {
/**
* Constructor.
*/
public ShapeException() {
super();
}
/**
* Constructor with description.
*/
public ShapeException( String s ) {
super( s );
}
}
___ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
./|n |||e |||t |||a |||r |||t |||- |||l |||a |||t |||i |||n |||o | \|/
.||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__| |
.||____|||__|||__|||__|||__|||__|||__|||__|||__| | |
.|/_____\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|__netart.org.uy __|
----- Original Message -----
_______________________________________________
Nettime-lat mailing list
Nettime-lat@nettime.org
http://amsterdam.nettime.org/cgi-bin/mailman/listinfo/nettime-lat